#include "stm32f10x.h"                  // Device header

#define MODE_INPUT                        0
#define MODE_OUTPUT_SPEED_10MHZ           1
#define MODE_OUTPUT_SPEED_2MHZ            2
#define MODE_OUTPUT_SPEED_50MHZ           3

#define CONF_OUTPUT_GENERAL_PUSH_PULL     0
#define CONF_OUTPUT_GENERAL_OPEN_DRAIN    1
#define CONF_OUTPUT_ALTERNATE_PUSH_PULL   2
#define CONF_OUTPUT_ALTERNATE_OPEN_DRAIN  3

#define CONF_INPUT_ANALOG                 0
#define CONF_INPUT_FLOATING               1
#define CONF_INPUT_PULL_UP_DOWN           2
#define CONF_INPUT_RESERVED               3

// 延时函数，微秒作为单位，利用系统嘀嗒定时器，72MHz，一次嘀嗒 1/72 us
void Delay_us(uint16_t us)
{
    // 1. 装载一个计数值，72 * us
    SysTick->LOAD = 72 * us;

    // 2. 配置，使用系统时钟（1），计数结束不产生中断（0），使能定时器（1）
    SysTick->CTRL = SysTick_CTRL_CLKSOURCE | SysTick_CTRL_ENABLE;

    // 3. 等待计数值变为0，判断CTRL标志位COUNTFLAG是否为1
    while ((SysTick->CTRL & SysTick_CTRL_COUNTFLAG) == 0)
    {}

    // 4. 关闭定时器
    SysTick->CTRL &= ~SysTick_CTRL_ENABLE;
}

void Delay_ms(uint16_t ms)
{
    while (ms--)
    {
        Delay_us(1000);
    }
}

void Delay_s(uint16_t s)
{
    while (s--)
    {
        Delay_ms(1000);
    }
}

int main(void)
{
    // 1. GPIOA模块的时钟配置: RCC_APB2ENR 寄存器
    RCC->APB2ENR |= RCC_APB2ENR_IOPAEN;

    // 2. GPIO PA0的工作模式配置：输出模式，推挽输出: GPIOA_CRL 寄存器
    GPIOA->CRL &= ~(0xF << (0 * 4));
    GPIOA->CRL |= MODE_OUTPUT_SPEED_50MHZ       << (0 * 4);
    GPIOA->CRL |= CONF_OUTPUT_GENERAL_PUSH_PULL << (0 * 4 + 2);

    // 2. GPIO PA1的工作模式配置：输出模式，推挽输出: GPIOA_CRL 寄存器
    GPIOA->CRL &= ~(0xF << (1 * 4));
    GPIOA->CRL |= MODE_OUTPUT_SPEED_50MHZ       << (1 * 4);
    GPIOA->CRL |= CONF_OUTPUT_GENERAL_PUSH_PULL << (1 * 4 + 2);

    // 2. GPIO PA8的工作模式配置：输出模式，推挽输出: GPIOA_CRH 寄存器
    GPIOA->CRH &= ~(0xF << (0 * 4));
    GPIOA->CRH |= MODE_OUTPUT_SPEED_50MHZ       << (0 * 4);
    GPIOA->CRH |= CONF_OUTPUT_GENERAL_PUSH_PULL << (0 * 4 + 2);

    // 3. PA0输出高电平, 熄灭LED: GPIOA_ODR 寄存器
    GPIOA->ODR |= GPIO_ODR_ODR0;
    // 3. PA1输出高电平, 熄灭LED: GPIOA_ODR 寄存器
    GPIOA->ODR |= GPIO_ODR_ODR1;
    // 3. PA8输出高电平, 熄灭LED: GPIOA_ODR 寄存器
    GPIOA->ODR |= GPIO_ODR_ODR8;

    while(1)
    {
        GPIOA->ODR &= ~GPIO_ODR_ODR0;
        Delay_ms(500);
        GPIOA->ODR |= GPIO_ODR_ODR0;

        GPIOA->ODR &= ~GPIO_ODR_ODR1;
        Delay_ms(500);
        GPIOA->ODR |= GPIO_ODR_ODR1;

        GPIOA->ODR &= ~GPIO_ODR_ODR8;
        Delay_ms(500);
        GPIOA->ODR |= GPIO_ODR_ODR8;
    }
}
